#include "Game.h"

IGame* createGame( HINSTANCE hInst, HWND hWnd )
{
	return new Game( hInst, hWnd );
}

Game::Game( HINSTANCE hInst, HWND hWnd ) :
	m_input( hInst, hWnd )
{
	// initialize camera
	m_camera.hand = Camera::RIGHTHANDED;

	m_camera.eye = float3( 0, 0, 20.f );
	m_camera.at  = float3( 0, 0, 0 );
	m_camera.up  = float3( 0, 1, 0 );

	m_camera.projectionType = Camera::PERSPECTIVE_FOV;
	m_camera.perspectiveFov.fovy = D3DXToRadian(45.f);
	m_camera.perspectiveFov.aspect = 1024.f/768.f;

	m_camera.zn = 1.0f;
	m_camera.zf = 100.0f;

	// initialize polygon
	m_polygon.push_back( float3( -0.3, -0.5, 0 ) );
	m_polygon.push_back( float3( 0.3, -0.5, 0 ) );
	m_polygon.push_back( float3( 0, 0.5, 0 ) );

	// initialize player polygon
	m_player.polygon = m_polygon;

	// reset meteor builder
	m_meteorBuilder = 0;
}

Game::~Game()
{
	m_polygonView.destroy();
	m_d3dDevice = 0;
}

void Game::onCreateGraphics( D3DDevice device )
{
	m_d3dDevice = device;
	m_polygonView.initialize( m_d3dDevice );
	m_polygonView.setup( m_polygon, float4( 1.0f, 1.0f, 1.0f, 1.0f ) );

	m_d3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CW );

	float44 world = identity44();
	float44 view = m_camera.view();
	float44 proj = m_camera.projection();

	m_d3dDevice->SetTransform( D3DTS_WORLD, &world );
	m_d3dDevice->SetTransform( D3DTS_VIEW, &view );
	m_d3dDevice->SetTransform( D3DTS_PROJECTION, &proj );

	// game-specific code
	m_player.view.initialize( m_d3dDevice );
	m_player.view.setup( m_player.polygon, float4(1.f,1.f,1.f,1.f) );

	createMeteorClasses();
}

void Game::onResetGraphics( D3DDevice device )
{
	//TODO: Add code to handle lost device ( resizing issue )

	m_d3dDevice = device;

	m_polygonView.destroy();
	m_polygonView.initialize( m_d3dDevice );
	m_polygonView.setup( m_polygon, float4( 1.0f, 1.0f, 1.0f, 1.0f ) );

	m_d3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CW );

	float44 view = m_camera.view();
	float44 proj = m_camera.projection();

	m_d3dDevice->SetTransform( D3DTS_VIEW, &view );
	m_d3dDevice->SetTransform( D3DTS_PROJECTION, &proj );
}

void Game::onLostGraphics()
{
}

void Game::onFrameMove(float dt)
{
	handleInput();
	meteorManagement(dt);
	m_player.body.step(dt);
	for(int i = 0; i < m_meteors.capacity(); i++ )
		if( m_meteors.occupied(i) )
			m_meteors[i].body.step(dt);
}

void Game::onFrameRender(float dt)
{
	m_player.view.render( m_player.body.world() );
	renderMeteors();
}

void Game::onDestroyGraphics()
{
}

void Game::handleInput()
{
	IInput::KEYSTATE keystate;
	keystate = m_input.keyState();

	if(keystate.keys[DIK_UP])
		m_player.body.addForceLocal( float3(0.f,10.f,0.f) );
	if(keystate.keys[DIK_LEFT])
		m_player.body.addTorqueLocal( float3(0.f,0.f,+3.f) );
	if(keystate.keys[DIK_RIGHT])
		m_player.body.addTorqueLocal( float3(0.f,0.f,-3.f) );
}

void Game::createMeteorClasses()
{
	for( int i = 0; i < 50; i++ )
		m_metClasses.insert( new MeteorClass(m_d3dDevice) );
}

void Game::meteorManagement(float dt)
{
	m_meteorBuilder += dt;
	while( m_meteorBuilder > 0.5 )
	{
		m_meteorBuilder -= 0.5f;
		Meteor meteor;
		meteor.classID = rand()%m_metClasses.size();
		meteor.body.pos = float3(rand()%21-10, rand()%21-10, 0.f);
		meteor.body.vel = float3(rand()%11-5,rand()%11-5,0);
		meteor.body.rotMomentum = float3(0,0,rand()%16*PI*2/512);
		meteor.body.invLocalInertia = m_metClasses[meteor.classID]->invInertia;
		meteor.body.invMass = m_metClasses[meteor.classID]->invMass;
		m_meteors.insert( meteor );
	}
}

void Game::renderMeteors()
{
	for( int i = 0; i < m_meteors.capacity(); i++ )
	{
		if( m_meteors.occupied( i ) )
		{
			m_metClasses[m_meteors[i].classID]->view.render(m_meteors[i].body.world());
		}
	}
}
